#include "util.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"
#include "daemonize.hpp"

#include <pthread.h>

class ServerTcp;

void transService(int sock, const std::string &clientIp, uint16_t clientPort)
{
    assert(sock >= 0);
    assert(!clientIp.empty());
    assert(clientPort >= 1024);

    char inbuffer[BUFFER_SIZE];
    while(true)
    {
        ssize_t s = read(sock, inbuffer, sizeof(inbuffer) - 1);
        if(s > 0)
        {
            inbuffer[s] = '\0';
            if(strcasecmp(inbuffer, "quit") == 0)
            {
                logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
                break;
            }
            logMessage(DEBUG, "trans before: %s[%d]>>> %s", clientIp.c_str(), clientPort, inbuffer);

            for(int i = 0; i < s; ++i)
            {
                if(isalpha(inbuffer[i]) && islower(inbuffer[i]))
                {
                    inbuffer[i] = toupper(inbuffer[i]);
                }
            }
            logMessage(DEBUG, "trans after: %s[%d]>>> %s", clientIp.c_str(), clientPort, inbuffer);

            write(sock, inbuffer, strlen(inbuffer));
        }
        else if(s == 0)
        {
            logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
            break;
        }
        else
        {
            logMessage(DEBUG, "%s[%d] - read: %s", clientIp.c_str(), clientPort, strerror(errno));
            break;
        }
    }

    close(sock);
    logMessage(DEBUG, "server close %d done", sock);
}

void execCommand(int sock, const std::string &clientIp, uint16_t clientPort)
{
    assert(sock >= 0);
    assert(!clientIp.empty());
    assert(clientPort >= 1024);

    char command[BUFFER_SIZE];
    while(true)
    {
        ssize_t s = read(sock, command, sizeof(command) - 1);
        if(s > 0)
        {
            command[s] = '\0';
            logMessage(DEBUG, "[%s:%d] exec [%s]", clientIp.c_str(), clientPort, command);

            std::string safe = command;
            if((std::string::npos != safe.find("rm")) || (std::string::npos != safe.find("unlink")))
            {
                break;
            }

            FILE *fp = popen(command, "r");
            if(fp == nullptr)
            {
                logMessage(WARINING, "exec %s failed, because: %s", command, strerror(errno));
                break;
            }
            char line[1024];
            while(fgets(line, sizeof(line) - 1, fp) != nullptr)
            {
                write(sock, line, strlen(line));
            }

            pclose(fp);
            logMessage(DEBUG, "[%s:%d] exec [%s] ... done", clientIp.c_str(), clientPort, command);
        }
        else if(s == 0)
        {
            logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
            break;
        }
        else
        {
            logMessage(DEBUG, "%s[%d] - read: %s", clientIp.c_str(), clientPort, strerror(errno));
            break;
        }
    }
}

class ThreadData
{
public:
    uint16_t clientPort_;
    std::string clientIp_;
    int sock_;
    ServerTcp *this_;
public:
    ThreadData(uint16_t port, std::string ip, int sock, ServerTcp *ts)
        :clientPort_(port), clientIp_(ip), sock_(sock), this_(ts)
    {}
};

class ServerTcp
{
public:
    ServerTcp(uint16_t port, const std::string &ip = "")
        : port_(port),
        ip_(ip),
        listenSock_(-1),
        tp_(nullptr),
        quit_(false)
    {}
    
    ~ServerTcp()
    {
        if(listenSock_ >= 0) close(listenSock_);
    }
public:
    void init()
    {
        // 1.创建socket
        listenSock_ = socket(AF_INET, SOCK_STREAM, 0);
        if(listenSock_ < 0)
        {
            logMessage(FATAL, "socket : %s", strerror(errno));
            exit(SOCKET_ERR);
        }
        // 2.bind绑定
        // 2.1 填充信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = PF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 2..2本地socket信息，bind
        if(bind(listenSock_, (const struct sockaddr *)&local, sizeof local) < 0)
        {
            logMessage(FATAL, "bind: %s", strerror(errno));
            exit(BIND_ERR);
        }
        logMessage(DEBUG, "bind: %s, %d", strerror(errno), listenSock_);
        // 3.监听socket
        if(listen(listenSock_, 5))
        {
            logMessage(FATAL, "listen : %s", strerror(errno));
            exit(LISTEN_ERR);
        }
        logMessage(DEBUG, "listen: %s, %d", strerror(errno), listenSock_);
        // 4.加载线程池
        tp_ = ThreadPool<Task>::getInstance();
    }

    // static void *threadRoutine(void *args)
    // {
    //     pthread_detach(pthread_self()); //设置线程分离
    //     ThreadData *td = static_cast<ThreadData *>(args);
    //     td->this_->transService(td->sock_, td->clinetIp_, td->clientPort_);
    //     delete td;
    //     return nullptr;
    // }

    void loop()
    {
        tp_->start();
        logMessage(DEBUG, "thread pool start success, thread num: %d", tp_->threadNum());
        while(!quit_)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 4.获取连接
            // 4.1 accept
            int serviceSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if(quit_) break;
            if(serviceSock < 0)
            {
                logMessage(WARINING, "accept: %s[%d]", strerror(errno), serviceSock);
                continue;
            }
            // 4.2 获取客户端基本信息
            uint16_t peerPort = ntohs(peer.sin_port);
            std::string peerIp = inet_ntoa(peer.sin_addr);
            // 5.提供服务

            //// 单进程
            // transService(serviceSock, peerIp, peerPort);
            
            //// 多进程1
            // pid_t id = fork();
            // assert(id != -1);
            // if(id == 0)
            // {
            //     close(listenSock_); //建议
            //     //子进程
            //     transService(serviceSock, peerIp, peerPort);
            //     exit(0); // 进入僵尸
            // }
            // // 父进程
            // close(serviceSock); //这一步是一定要做的！

            //// 多进程2
            // // 爷爷进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     // 爸爸进程
            //     close(listenSock_);//建议
            //     // 又进行了一次fork，让 爸爸进程
            //     if(fork() > 0) exit(0);
            //     // 孙子进程 -- 就没有爸爸 -- 孤儿进程 -- 被系统领养 -- 回收问题就交给了系统来回收
            //     transService(serviceSock, peerIp, peerPort);
            //     exit(0);
            // }
            // // 父进程
            // close(serviceSock); //这一步是一定要做的！
            // // 爸爸进程直接终止，立马得到退出码，释放僵尸进程状态
            // pid_t ret = waitpid(id, nullptr, 0); //就用阻塞式
            // assert(ret > 0);
            // (void)ret;


            //// 多线程
            // ThreadData *td = new ThreadData(peerPort, peerIp, serviceSock, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, threadRoutine, (void*)td);

            //// 线程池1
            // Task t(serviceSock, peerIp, peerPort, std::bind(&ServerTcp::transService, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            // tp_->push(t);

            //// 线程池2
            // Task t(serviceSock, peerIp, peerPort, transService);
            // tp_->push(t);

            //// 线程池3
            Task t(serviceSock, peerIp, peerPort, execCommand);
            tp_->push(t);
        }
    }

    bool quitServer()
    {
        quit_ = true;
        return true;
    }
private:
    int listenSock_;
    uint16_t port_;
    std::string ip_;
    ThreadPool<Task> *tp_;
    bool quit_;
};

static void Usage(std::string proc)
{
    std::cerr << "Usage\n\t" << proc << " port ip" << std::endl;
    std::cerr << "example\n\t" << proc << " 8080 127.0.0.1\n" << std::endl;
}

ServerTcp *svrp = nullptr;

void sigHandler(int signo)
{
    if(signo == 3 && svrp != nullptr) svrp->quitServer();
    logMessage(DEBUG, "server quit save!");
}

int main(int argc, char *argv[])
{
    if(argc != 2 && argc != 3)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }

    uint16_t port = atoi(argv[1]);
    std::string ip;
    if(argc == 3) ip = argv[2];

    signal(3, sigHandler);

    ServerTcp svr(port, ip);
    svr.init();
    svrp = &svr;
    svr.loop();

    return 0;
}
